#pragma once

#include "ExecutionPlan.h"
#include "SymbolTable.h"
#include <memory>
#include <vector>
#include <unordered_set>

namespace MiniDB {

/**
 * 谓词下推优化器
 *
 * 功能：
 * 1. 将WHERE子句中的条件尽可能地下推到执行树的底部
 * 2. 将过滤条件推到扫描算子之前，减少需要处理的数据量
 * 3. 支持复杂表达式的分解和下推
 */
class PredicatePushdownOptimizer {
public:
    explicit PredicatePushdownOptimizer(SymbolTable& symbol_table);
    ~PredicatePushdownOptimizer() = default;

    /**
     * 优化执行计划，应用谓词下推
     * @param plan 要优化的执行计划
     * @return 优化后的执行计划
     */
    std::unique_ptr<ExecutionPlan> optimize(std::unique_ptr<ExecutionPlan> plan);

private:
    SymbolTable& symbol_table_;

    /**
     * 优化算子树
     * @param operator 要优化的算子
     * @return 优化后的算子
     */
    std::shared_ptr<PlanOperator> optimizeOperator(std::shared_ptr<PlanOperator> op);

    /**
     * 优化Filter算子
     * @param filter_op Filter算子
     * @return 优化后的算子
     */
    std::shared_ptr<PlanOperator> optimizeFilter(std::shared_ptr<FilterOperator> filter_op);

    /**
     * 优化Project算子
     * @param project_op Project算子
     * @return 优化后的算子
     */
    std::shared_ptr<PlanOperator> optimizeProject(std::shared_ptr<ProjectOperator> project_op);

    /**
     * 检查表达式是否可以下推到指定表
     * @param expr 要检查的表达式
     * @param table_name 目标表名
     * @return 是否可以下推
     */
    bool canPushDownToTable(std::shared_ptr<Expression> expr, const std::string& table_name);

    /**
     * 分解复杂表达式，返回可以下推的部分
     * @param expr 要分解的表达式
     * @param table_name 目标表名
     * @return 可以下推的表达式列表
     */
    std::vector<std::shared_ptr<Expression>> extractPushablePredicates(
        std::shared_ptr<Expression> expr, const std::string& table_name);

    /**
     * 从表达式中提取只涉及指定表的条件
     * @param expr 要分析的表达式
     * @param table_name 目标表名
     * @return 提取的条件表达式
     */
    std::shared_ptr<Expression> extractTableSpecificPredicate(
        std::shared_ptr<Expression> expr, const std::string& table_name);

    /**
     * 合并多个条件表达式
     * @param predicates 要合并的条件列表
     * @return 合并后的表达式
     */
    std::shared_ptr<Expression> combinePredicates(
        const std::vector<std::shared_ptr<Expression>>& predicates);

    /**
     * 检查表达式是否只涉及指定表的列
     * @param expr 要检查的表达式
     * @param table_name 目标表名
     * @return 是否只涉及指定表的列
     */
    bool involvesOnlyTableColumns(std::shared_ptr<Expression> expr, const std::string& table_name);

    /**
     * 递归检查表达式中的所有列引用
     * @param expr 要检查的表达式
     * @param table_name 目标表名
     * @param column_refs 找到的列引用集合
     * @return 是否只涉及指定表的列
     */
    bool checkColumnReferences(std::shared_ptr<Expression> expr,
                              const std::string& table_name,
                              std::unordered_set<std::string>& column_refs);

    /**
     * 获取表达式中引用的所有表名
     * @param expr 要分析的表达式
     * @return 引用的表名集合
     */
    std::unordered_set<std::string> getReferencedTables(std::shared_ptr<Expression> expr);

    /**
     * 创建Filter算子
     * @param child 子算子
     * @param condition 过滤条件
     * @return Filter算子
     */
    std::shared_ptr<FilterOperator> createFilter(std::shared_ptr<PlanOperator> child,
                                                 std::shared_ptr<Expression> condition);

    /**
     * 移除冗余的Filter算子
     * @param op 要处理的算子
     * @return 处理后的算子
     */
    std::shared_ptr<PlanOperator> removeRedundantFilters(std::shared_ptr<PlanOperator> op);
};

} // namespace MiniDB
